/**
 * <p>Copyright:Copyright(c) 2019</p>
 * <p>Company:Professional</p>
 * <p>Package:org.cesgroup.course.proxy.aspect</p>
 * <p>File:ProxyAspect.java</p>
 * <p>类更新历史信息</p>
 * @todo chanlong(陈龙) 创建于 Sep 2, 2019 3:20:09 PM
 */
package org.cesgroup.course.proxy.aspect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.cesgroup.course.proxy.annotation.Proxy;
import org.springframework.beans.BeansException;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import cn.hutool.core.util.ReflectUtil;

/**
 * <p>描述: </p>
 * <p>Company: Professional</p>
 * @author chanlong(陈龙)
 * @date Sep 2, 2019 3:20:09 PM
 * @version 1.0.2019
 */
@Aspect @Component
public class ProxyAspect implements ApplicationContextAware {
	
	@Around("@annotation(org.cesgroup.course.proxy.annotation.Proxy)")
	public Object performed(final ProceedingJoinPoint point) {
		Object returnObject = null;
		try {
			// 获取“@Proxy”注解及属性
			Proxy proxy = getAnnotation(point, Proxy.class);
			String targetMethod = proxy.targetMethod();
			Class<?> targetClass = proxy.targetClass();
			Class<?> handlerClass = proxy.handlerClass();
			
			// 获取代理对象及代理Handler
			Object bean = applicationContext.getBean(targetClass);
			Constructor<?> constructor = handlerClass.getConstructor(Object.class);
			InvocationHandler handler  = (InvocationHandler) constructor.newInstance(bean);
			
			// 装配代理对象
			ClassLoader classLoader = targetClass.getClassLoader();
			Class<?> superclass = targetClass;
			Enhancer hancer = new Enhancer();
	        hancer.setClassLoader(classLoader);
	        hancer.setSuperclass(superclass);
	        hancer.setCallback(handler);
	        
	        // 通过代理调用方法
	        Object create = hancer.create();
	        returnObject = ReflectUtil.invoke(create, targetMethod, point.getArgs());
	        
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return returnObject;
	}
	
	/* 从AOP切面中，通过方法签名，获取被拦截方案 */
	protected Method getMethodBySignature(final JoinPoint point){
		MethodSignature signature = (MethodSignature)point.getSignature();
		return signature.getMethod();
	}
	
	/* 从AOP切面中，获取被拦截方法上的指定注解 */
	protected Proxy getAnnotation(final JoinPoint joinPoint, final Class<Proxy> annotionClass) throws Exception {
		Method method = getMethodBySignature(joinPoint);
		return  method.getAnnotation(annotionClass);
	}
	
	/**
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 * @author chanlong(陈龙)
	 * @date Sep 2, 2019 4:05:02 PM
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	
	private ApplicationContext applicationContext;
}
